------------------------------------- Chapitre VIII - Cryptographie -------------------------------------
Cryptographie symétrique : un exemple de Blowfish - 2/4
Trouver un serial valide :
On lance le logiciel, on a la page d'accueil suivante :
Le logiciel demande un couple name / serial :
On va maintenant taper le couple email address (toto@gmail.com) / license code (0123456789).
On obtient alors l'erreur suivante :
En posant un breakpoint sur l'API MessageBoxA, on remonte facilement à l'appel dans mfc42.dll (encapsulation de l'API) :
puis à l'appel dans l'exécutable :
On voit donc bien que le paramètre (affecté à EAX) que l'on récupère en sortie de fonction doit être
inférieur à 1869Fh sans être nul pour autant...
A quoi correspond ce dword affecté à EAX ?
Essayons d'abord de retrouver les différentes fonctions de Blowfish.
Phase d'extension (ou initialisation) :
En traçant jusqu'en 00416537, on finit par avoir ceci dans la pile :
Ça y est, on a notre clé privée !
Note : Attention, la clef privée peut ne pas être une chaîne.
On en a un exemple avec Drive Power Manager v1.10 :
On peut commenter le code pour le rendre plus compréhensible :
La taille de la clef (19h) a été déterminée par :
00416516 |. E8 81150200 CALL <JMP.&MFC42.#537>
Cet appel encapsule en fait l'API lstrlenA :
En traçant dans Blowfish_Init( ), on retombe sur l'initialisation des S-Boxes et du tableau P, qui sont des tableaux
de valeurs constantes...
Les valeurs dans les S-Boxes sont tirées du nombre Pi exprimé en hexadécimal.
La routine suivante recopie en mémoire les 4 S-Boxes :
S-Box : 256 éléments (DWORDs)
Le premier élément de la 1ère S-Box est :
D1310BA6h
Il est notamment utilisé pour reconnaître la présence de Blowfish.
Il peut cependant arriver que certains programmes implémentent des versions modifiées de cet algorithme.
Ainsi, certains outils comme PEiD ou RDG peuvent échouer dans la détection, donc faites attention !
Voici, ensuite, la routine, qui effectue un XOR entre le P-Array et la clef choisie :
Si la taille de la clef (en bits) devient inférieur à l'index dans le P-array (18*32 bytes), on reprend le début de la clef...
P-array : 18 éléments (DWORDs)
Le premier élément du tableau P est :
243F6A88h
Voici le context (qui comprend le tableau P et les 4 S-Boxes) avant l'exécution de cette routine :
En vert, on a le 1er élément de la 1ère S-Box.
Le context devient après l'exécution de cette routine :
Dans la phase d'extension d'initialisation, on trouve des appels à la fonction de chiffrement ( Blowfish_encrypt ( ) ).
Cette source en C le confirme :
Voici les 2 appels à la fonction Blowfish_encrypt ( ) dans Blowfish_Initialization ( ) :
Dans Blowfish_Initialization ( ), le premier chiffrement par la fonction Blowfish_encrypt ( ), concerne le Tableau P,
le deuxième, les 4 S-Boxes.
Il faut donc faire attention à ne pas confondre les appels à la fonction Blowfish_encrypt ( ) dans l'initialisation à un
éventuel autre appel, qui, lui concernerait le chiffrement des données du serial.
Voici cette fonction Blowfish_encrypt ( ) :
Ici, on voit le réseau de Feistel à l'oeuvre ! On est au coeur de la fonction Blowfish_encrypt ( ).
On observe la valeur 10h (qui correspond aux 16 tours effectuées).
Le processus entier se base sur des opérations XOR, ces XORs se produisent entre deux données de 32 bits chacune.
On peut également remarquer que la fonction Blowfish_encrypt ( ) est appelée uniquement deux fois (par la fonction d'initialisation).
Ceci peut nous laisser émettre l'hypothèse que le serial contient des données, qui seront déchiffrées par Blowfish (la
fonction Blowfish_decrypt ( ) ).
Le reverser devra donc chiffrer pour retrouver le bon serial.
Dans la plupart des cas, c'est cependant l'inverse, le programme utilise la fonction Blowfish_Init ( ) et la fonction Blowfish_encrypt
( ).
Le reverser n'aura donc qu'à connaître la clef secrète et à implémenter une fonction de déchiffrement...
Voici la fonction GetByte (X,Y), appelée par Blowfish_encrypt ( ) :
La fonction de déchiffrement est appelée deux fois dans l'initialisation et s'applique au Tableau P, puis aux 4 S-Boxes.
La fonction Blowfish_Init( ) s'achève alors. On peut donc passer à la phase suivante...